/**
 * 2025/01/01 - 2025/12/31
 */
package com.snail.server.database.engine.ddl.operation.mysql;

import com.snail.server.database.engine.ddl.model.field.FieldAdd;
import com.snail.server.database.engine.ddl.model.field.FieldAlter;
import com.snail.server.database.engine.ddl.model.field.FieldDrop;
import com.snail.server.database.engine.ddl.model.field.FieldMo;
import com.snail.server.database.engine.ddl.model.index.IndexAdd;
import com.snail.server.database.engine.ddl.model.index.IndexAlter;
import com.snail.server.database.engine.ddl.model.index.IndexDrop;
import com.snail.server.database.engine.ddl.model.index.IndexMo;
import com.snail.server.database.engine.ddl.model.table.TableAlter;
import com.snail.server.database.engine.ddl.model.table.TableCreate;
import com.snail.server.database.engine.ddl.model.table.TableQuery;
import com.snail.server.database.engine.ddl.operation.AbstractDDLOperation;
import com.snail.starter.commons.exception.BizException;
import com.snail.server.database.engine.datasource.enums.DataSourceTypeEnum;
import com.snail.server.database.engine.error.DatabaseEngineErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zgadmin
 * @date 2025/9/8 09:42
 */
@Slf4j
@Component
public class MySqlDDLOperation extends AbstractDDLOperation {

    @Override
    public boolean support(DataSourceTypeEnum datasourceType) {
        return DataSourceTypeEnum.MYSQL.equals(datasourceType);
    }

    @Override
    public String ignoreKeyword(String keyword) {
        return handlerKeyword(keyword);
    }

    @Override
    public boolean createTable(Long datasourceId, TableCreate tableCreate) {
        if (null == tableCreate || null == tableCreate.getName() || "".equals(tableCreate.getName())) {
            log.error("createTable, table name is empty:{}", tableCreate);
            return false;
        }
        StringBuilder createTableSql = new StringBuilder("CREATE TABLE ")
                .append(handlerKeyword(tableCreate.getName()))
                .append("(");
        List<FieldMo> fields = tableCreate.getFields();
        if (null != fields && !fields.isEmpty()) {
            createTableSql.append(fields.stream().map(MySqlDDLOperation::fieldToSql).collect(Collectors.joining(",")));
        }
        List<IndexMo> indexes = tableCreate.getIndexes();
        if (null != indexes && !indexes.isEmpty()) {
            createTableSql.append(",").append(indexes.stream().map(this::indexToSql).collect(Collectors.joining(",")));
        }
        return execute(createTableSql.append(")").toString());
    }

    @Override
    public boolean alterTable(Long datasourceId, TableAlter tableAlter) {
        return false;
    }

    @Override
    public boolean dropTable(Long datasourceId, String tableName) {
        return false;
    }

    @Override
    public boolean queryTable(Long datasourceId, TableQuery tableQuery) {
        return false;
    }

    @Override
    public boolean addField(Long datasourceId, FieldAdd fieldAdd) {
        return false;
    }

    @Override
    public boolean alterField(Long datasourceId, FieldAlter fieldAlter) {
        return false;
    }

    @Override
    public boolean dropField(Long datasourceId, FieldDrop fieldDrop) {
        return false;
    }

    @Override
    public boolean addIndex(Long datasourceId, IndexAdd indexAdd) {
        return false;
    }

    @Override
    public boolean alterIndex(Long datasourceId, IndexAlter indexAlter) {
        return false;
    }

    @Override
    public boolean dropIndex(Long datasourceId, IndexDrop indexDrop) {
        return false;
    }

    public static String handlerKeyword(String keyword) {
        return "`" + keyword + "`";
    }

    public static String fieldToSql(FieldMo field) {
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append(handlerKeyword(field.getName()));
        switch (field.getType()) {
            case TEXT:
                fieldSql.append(BLANK).append("VARCHAR(").append(field.getIDigits()).append(")");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDefaultValue()) {
                    fieldSql.append(BLANK).append("DEFAULT").append(BLANK).append("'").append(field.getDefaultValue()).append("'");
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            case LONG_TEXT:
                fieldSql.append(BLANK).append("TEXT");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDefaultValue()) {
                    fieldSql.append(BLANK).append("DEFAULT").append(BLANK).append("'").append(field.getDefaultValue()).append("'");
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            case INT:
                fieldSql.append(BLANK).append("SMALLINT(").append(null == field.getIDigits() || 0 == field.getIDigits() ? 4 : field.getIDigits()).append(")");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDefaultValue()) {
                    fieldSql.append(BLANK).append("DEFAULT").append(BLANK).append(field.getDefaultValue());
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            case BIGINT:
                fieldSql.append(BLANK).append("BIGINT(").append(null == field.getIDigits() || 0 == field.getIDigits() ? 4 : field.getIDigits()).append(")");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDefaultValue()) {
                    fieldSql.append(BLANK).append("DEFAULT").append(BLANK).append(field.getDefaultValue());
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            case DOUBLE:
                fieldSql.append(BLANK).append("DECIMAL(")
                        .append(null == field.getIDigits() ? 0 : field.getIDigits())
                        .append(",")
                        .append(null == field.getDDigits() ? 0 : field.getDDigits())
                        .append(")");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDefaultValue()) {
                    fieldSql.append(BLANK).append("DEFAULT").append(BLANK).append(field.getDefaultValue());
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            case DATETIME:
                fieldSql.append(BLANK).append("DATETIME");
                if (field.getNotNull().getBoolean()) {
                    fieldSql.append(BLANK).append("NOT NULL");
                }
                if (null != field.getDescription()) {
                    fieldSql.append(BLANK).append("COMMENT").append(BLANK).append("'").append(field.getDescription()).append("'");
                }
                return fieldSql.toString();
            default:
                throw BizException.of(DatabaseEngineErrorCode.NOT_SUPPORT_FIELD_TYPE, new Object[]{field.getType().getDesc()});
        }
    }

}